
import { _decorator, Component, director } from 'cc';
import { WebSocketConnector } from './WebSocketConnector';
import { ProtocolParser } from './ProtocolParser';
import { EventManager } from '../eventManager/EventManager';
import { EventType } from '../eventManager/EventType';

const { ccclass, property } = _decorator;

@ccclass('NetworkManager')
export class NetworkManager extends Component {
    private static _instance: NetworkManager = null;
    private _connector: WebSocketConnector;
    private _parser: ProtocolParser;
    private _reconnectAttempts = 0;
    private _maxReconnectAttempts = 5;
    private _pingInterval = 30000;
    private _pingTimer: number;
    private _requestCallbacks: Map<number, Function> = new Map();
    private _requestIdCounter = 0;
    private _eventManager: EventManager;

    public static getInstance(): NetworkManager {
        return this._instance;
    }

    onLoad() {
        if (NetworkManager._instance) {
            this.destroy();
            return;
        }
        NetworkManager._instance = this;
        director.addPersistRootNode(this.node);
        this._eventManager = EventManager.getInstance();

        this._connector = new WebSocketConnector();
        this._parser = new ProtocolParser();

        this.initEventListeners();
    }

    private initEventListeners() {
        this._eventManager.on(EventType.NET_OPEN, this.onConnected.bind(this));
        this._eventManager.on(EventType.NET_CLOSE, this.onDisconnected.bind(this));
        this._eventManager.on(EventType.NET_MESSAGE, this.onMessageReceived.bind(this));
        this._eventManager.on(EventType.NET_ERROR, this.onError.bind(this));
    }

    public connect(url: string): void {
        this._connector.connect(url);
    }

    private onConnected(): void {
        console.log('WebSocket connected');
        this._reconnectAttempts = 0;
        this.startHeartbeat();
        this._eventManager.emit(EventType.NET_CONNECT);
    }

    private onDisconnected(): void {
        console.log('WebSocket disconnected');
        this.stopHeartbeat();
        this.tryReconnect();
        this._eventManager.emit(EventType.NET_DISCONNECT);
    }

    private tryReconnect(): void {
        if (this._reconnectAttempts < this._maxReconnectAttempts) {
            this._reconnectAttempts++;
            const delay = Math.min(1000 * this._reconnectAttempts, 5000);
            setTimeout(() => this._connector.reconnect(), delay);
        }
    }

    private startHeartbeat(): void {
        this._pingTimer = setInterval(() => {
            this.send(0xFFFF, { timestamp: Date.now() });
        }, this._pingInterval);
    }

    private stopHeartbeat(): void {
        clearInterval(this._pingTimer);
    }

    public send(protocolId: number, data: any, callback?: Function): void {
        if (callback) {
            const requestId = ++this._requestIdCounter;
            this._requestCallbacks.set(requestId, callback);
            data.__requestId = requestId;
        }

        const buffer = this._parser.encode(protocolId, data);
        this._connector.send(buffer);
    }

    private onMessageReceived(data: ArrayBuffer): void {
        try {
            const { protocolId, payload, requestId } = this._parser.decode(data);

            if (requestId && this._requestCallbacks.has(requestId)) {
                const callback = this._requestCallbacks.get(requestId);
                callback(payload);
                this._requestCallbacks.delete(requestId);
            } else {
                this._eventManager.emit(EventType[`NET_MESSAGE_${protocolId}`], payload);
            }
        } catch (error) {
            console.error('Message parse error:', error);
        }
    }


    private onError(error: any): void {
        console.error('WebSocket error:', error);
    }

    public registerProtocol(protocolId: number, handler: Function): void {
        this._parser.registerProtocol(protocolId, handler);
    }
}
